package core.config;

import core.util.JacksonUtils;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableRabbit
public class RabbitConfig {

    private RabbitInitConfig rabbitInitConfig;

    public RabbitConfig(RabbitInitConfig rabbitInitConfig) {
        this.rabbitInitConfig = rabbitInitConfig;
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(rabbitInitConfig.rabbitConnectionFactory());
        //设置发送消息的消息转换器
        template.setMessageConverter(messageConverter());
        return template;
    }

    // 这个消息转换器是序列化为json，利用jackson，所以需要jackson的依赖
    @Bean
    public Jackson2JsonMessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter(JacksonUtils.getObjectMapper());
    }

    /**
     * 消费mq消息时如果出现异常，会导致消息不会自动确认，并反复进行重试
     * 见https://juejin.cn/post/6987623158840819720的说明，见
     * https://www.baeldung.com/spring-amqp-error-handling的错误处理方法
     * <p>
     * 要处理重试可以通过factory.setRetryTemplate完成，麻烦，
     * spring boot处理重试就比较方便
     *
     * @return
     */
    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(rabbitInitConfig.rabbitConnectionFactory());
        // spring容器启动时如果发现没有rabbit监听的队列存在会抛异常，
        // 导致spring容器不能正确启动，进而影响tomcat的正常启动
        // 设置下面的选项就不把队列不存在当成致命错误，能启动spring容器
        // 也会尝试连接队列，队列不存在时仍然会有异常信息输出，建议设置上
        // 但最好是先创建相关的队列，避免队列不存在的异常
        factory.setMissingQueuesFatal(false);

        //设置接收消息的消息转换器
        factory.setMessageConverter(messageConverter());
        return factory;
    }

}